# encoding: utf-8


"""

@author: tongzhenguo

@time: 2021/5/16 下午2:21

@desc:

粗排
根据一些可量化的指标加权排名(比如市值、ROE等)截断为前5条股票；


"""
import numpy as np
import pandas as pd
from collect_stock_data import StockBase
from common import array_min
from const import PROJ_HOME, TRADE_CAL_FILE
from date_util import last_trade_date, last_year, now_quarter, last_n_year
from mongo_db import MongoDB


class StockRank(StockBase):
    def __init__(self):
        super().__init__()
        self.db_name = "stock"
        self.collection_name = "stock"
        self.mongo_db = MongoDB(uri="mongodb://127.0.0.1:27017", database=self.db_name)
        # 年度财报时间
        self.year = int(last_year())
        # 季度财报时间
        self.quarter = int(now_quarter())
        # self.date = 20210611
        # 最近交易日时间，18点之后更新当日数据
        trade_cal_df = pd.read_csv(TRADE_CAL_FILE, dtype={"cal_date": str, "is_open": str})
        self.date = last_trade_date(trade_cal_df)

    def linear_weighted_rank(self, data, cols, weights):
        """线性加权score=sum(Wi * Xi)
        举例cols=["pe","roe"],weights=[-2,0.8]代表score=-2*pe + 0.8*roe
        """
        data["score"] = 0
        for col, weight in zip(cols, weights):
            data["score"] = data["score"] + weight * data[col].apply(np.float32)
        data = data.sort_values("score", ascending=False)
        return data

    def points_evaluation_card(self, data):
        """ 《价值投资赢家之道》王建军
        市盈率分段<=8,8-15,15-23,>30
        市净率分段<=1,1-4,4-7,7-9,>9
        10年净资产收益率分段>=20%,15%-20%,10%-15%,5%-10%
        3年资产负债率分段<=30%,30%-50%,>50%
        5年毛利率>=30%,10%-30%,<10%
        营业总收入增长率>=8%,3%-8%,<3%
        同比应收款减少>=10%,增加<=30%,增加>30%
        存货
        股东权益增长
        其他
        举例col_list=["pe","row"],bin_list=["8,15,23","1,4,7"],score_list=["2,1.5,1.2,1.0","2,1.8,0.8,0.5"]
        其中col_list是特征集合，bin_list是分段端点数组的字符串，score_list是评分数组的字符串
        """

        def encode(val, splits, index):
            """
            独热编码,分区离散化
            判断当前值对应编码是否为index；是1，否0
            """
            # 约束：分桶区间是严格升序的，否则抛出异常
            if len(splits) < 1:
                raise RuntimeError("error len(splits) < 1")
            pre = splits[0]
            for i in range(1, len(splits)):
                if pre >= splits[i]:
                    raise RuntimeError("splits must be ascending !!!")

            if index == 0:
                return 1 if val <= splits[index] else 0
            elif index == len(splits):
                return 1 if val > splits[-1] else 0
            return 1 if splits[index - 1] < float(val) <= splits[index] else 0

        # one-hot编码转换成rank_v1可以执行的格式，然后线性加权
        # 列名：pe_1,值0或1
        weights = []
        columns = []
        for col, bins, scores in zip(self.columns, self.bin_list, self.score_list):
            bins_split = list(map(float, bins.split(",")))
            weight_list = list(map(float, scores.split(",")))
            for ix in range(len(bins_split) + 1):
                col_name = "%s_%s" % (col, ix)
                columns.append(col_name)
                weights.append(weight_list[ix])
                data[col_name] = data[col].apply(lambda x: encode(float(x), bins_split, ix))
        data = self.linear_weighted_rank(data, columns, weights)
        return data

    def make_points_evaluation_card_data(self):
        columns = ["_id", "2020年度-股票简称", "%s日-滚动市盈率" % self.date, "%s日-市净率" % self.date]
        for i in range(1, 11):
            columns.append("%s年度-净资产收益率(%%)" % last_n_year(i, "str", format="YYYY"))
        for i in range(1, 4):
            columns.append("%s年度-资产负债率(%%)" % last_n_year(i, "str", format="YYYY"))
        for i in range(1, 6):
            columns.append("%s年度-销售毛利率(%%)" % last_n_year(i, "str", format="YYYY"))
            # columns.append("%s年度-销售毛利率(%%)" % last_n_year(i, "str", format="YYYY"))
            # 单位也是百分数
            # 净利润增长率 = ROE×（1-分红率）= 股东权益增长率
            columns.append("%s年度-净利润同比" % last_n_year(i, "str", format="YYYY"))
        columns.append("%s年度-营业总收入同比" % self.year)
        for i in range(1, 3):
            columns.append("%s年度-1-2年以内其它应收款(元)" % last_n_year(i, "str", format="YYYY"))
            columns.append("%s年度-2-3年以内其它应收款(元)" % last_n_year(i, "str", format="YYYY"))
            columns.append("%s年度-3年以内其它应收款(元)" % last_n_year(i, "str", format="YYYY"))
            columns.append("%s年度-资产-存货" % last_n_year(i, "str", format="YYYY"))
        code_list = pd.read_csv(PROJ_HOME + "/data/自选股/自选股.csv", dtype=str)["code"].to_list()
        data = self.mongo_db.fetch_data(self.collection_name, {"_id": {"$in": code_list}}, columns)

        self.columns = ["%s日-滚动市盈率" % self.date, "%s日-市净率" % self.date]
        self.bin_list = ["8,15,23,30", "1,4,7,9"]
        self.score_list = ["2,1.5,1,0.5,0", "2,1.5,1,0.5,0"]

        data["连续10年净资产收益率"] = ""
        for i in range(1, 11):
            col = "%s年度-净资产收益率(%%)" % last_n_year(i, "str", format="YYYY")
            data["连续10年净资产收益率"] += data[col] + ","
        data["连续3年净资产收益率"] = data["连续10年净资产收益率"].apply(lambda x: array_min(x.split(",")[:3], 0))
        data["连续10年净资产收益率"] = data["连续10年净资产收益率"].apply(lambda x: array_min(x.split(","), 0))
        columns.append("连续10年净资产收益率")
        columns.append("连续3年净资产收益率")
        self.bin_list.append("10,15,20")
        self.bin_list.append("10")
        self.score_list.append("0,1.0,1.5,2")
        self.score_list.append("0.5,0")

        data["连续3年资产负债率"] = ""
        for i in range(1, 4):
            col = "%s年度-资产负债率(%%)" % last_n_year(i, "str", format="YYYY")
            data["连续3年资产负债率"] += data[col] + ","
        data["连续3年资产负债率"] = data["连续3年资产负债率"].apply(lambda x: array_min(x.split(","), 0))
        columns.append("连续3年资产负债率")
        self.bin_list.append("30,50")
        self.score_list.append("1,0.5,0")

        data["连续5年销售毛利率"] = ""
        for i in range(1, 6):
            col = "%s年度-销售毛利率(%%)" % last_n_year(i, "str", format="YYYY")
            data["连续5年销售毛利率"] += data[col] + ","
        data["连续5年销售毛利率"] = data["连续5年销售毛利率"].apply(lambda x: array_min(x.split(","), 0))
        self.columns.append("连续5年销售毛利率")
        self.bin_list.append("10,30")
        self.score_list.append("0,0.5,1")

        self.columns.append("%s年度-营业总收入同比" % self.year)
        self.bin_list.append("3,8")
        self.score_list.append("0,0.25,0.5")

        base_col = "%s年度-应收款" % last_n_year(2, "str", format="YYYY")
        cur_col = "%s年度-应收款" % last_n_year(1, "str", format="YYYY")
        data[base_col] = 0
        data[cur_col] = 0
        for i in range(1, 3):
            year = last_n_year(i, "str", format="YYYY")
            col = "%s年度-应收款" % year
            data[col] = data[col] + data["%s年度-1-2年以内其它应收款(元)" % year].apply(np.float32) + \
                        data["%s年度-2-3年以内其它应收款(元)" % year].apply(np.float32) + \
                        data["%s年度-3年以内其它应收款(元)" % year].apply(np.float32)
        data["应收款同比减少"] = data[base_col] / data[cur_col] - 1
        self.columns.append("应收款同比减少")
        self.bin_list.append("-0.3,0.1")
        self.score_list.append("0,0.25,0.5")

        for i in range(1, 3):
            year = last_n_year(i, "str", format="YYYY")
            col = "%s年度-资产-存货" % year
            data[col] = data[col].apply(np.float32)
        base_col = "%s年度-资产-存货" % last_n_year(2, "str", format="YYYY")
        cur_col = "%s年度-资产-存货" % last_n_year(1, "str", format="YYYY")
        data["存货同比减少"] = data[base_col] / data[cur_col] - 1
        self.columns.append("存货同比减少")
        self.bin_list.append("-0.2,0.1")
        self.score_list.append("0,0.25,0.5")

        data["连续5年股东权益增长率"] = ""
        for i in range(1, 6):
            col = "%s年度-净利润同比" % last_n_year(i, "str", format="YYYY")
            data["连续5年股东权益增长率"] += data[col] + ","
        data["连续5年股东权益增长率"] = data["连续5年股东权益增长率"].apply(lambda x: array_min(x.split(","), 0))
        self.columns.append("连续5年股东权益增长率")
        self.bin_list.append("5")
        self.score_list.append("0,1")
        return data


if __name__ == "__main__":
    ss = StockRank()
    data = ss.make_points_evaluation_card_data()
    data = ss.points_evaluation_card(data)
    print(data[["_id", "score"]])
